# -*- coding: utf-8 -*-

import sys, os, getopt, commands
import _read_xml_ as read_xml


# -----------------------------------------------------------------------------
# global variables
# -----------------------------------------------------------------------------

MODE_LIST = ['normal', 'cross']

filename_dev  = ''
filename_test = ''
is_dev_type  = None
is_test_type = None

mode = ''
do_debug = False
log_dir_name = 'log'

algorithm = 'without_classias'
params = dict() # parameters for training
ALGORITHM_LIST = ['without_classias', 'lbfgs.logistic', 'averaged_perceptron',
                  'pegasos.logistic', 'pegasos.hinge',
                  'truncated_gradient.logistic', 'truncated_gradient.hinge']

sep_num = 10

do_multi_classify = False
do_apply_sigmoid  = True


# -----------------------------------------------------------------------------
# parse command-options
# -----------------------------------------------------------------------------
def getopts():
    global filename_dev, filename_test, mode, do_debug, \
           log_dir_name, algorithm, sep_num, param, \
           do_apply_sigmoid
    
    mode = sys.argv[1].strip()
    args = sys.argv[2:]

    if not mode in MODE_LIST:
        raise ValueError
    else:
        print 'mode :', mode

    opts, args = getopt.getopt(args, 'a:d:g:l:p:t:Dm', ['no-sigmoid'])

    if opts:
        print 'options :'
        
    for opt, val in opts:

        if opt == '-a':
            algorithm = val
            if not algorithm in ALGORITHM_LIST:
                raise ValueError
            else:
                print ' '*4 + 'algorithm :', algorithm

        if opt == '-d':
            filename_dev = val
            print ' '*4 + 'filename-dev :', filename_dev
            
        if opt == '-g':
            sep_num = int(val)
            print ' '*4 + 'separation-num :', sep_num

        if opt == '-l':
            log_dir_name = val
            print ' '*4 + 'log-directory-name :', log_dir_name

        if opt == '-p':
            spl = val.split('=')
            if len(spl) == 2:
                name  = spl[0]
                value = spl[1]
                params[name] = value
                print ' '*4 + 'param[%s] :'%name, value
            else:
                raise ValueError
            
        if opt == '-t':
            filename_test = val
            print ' '*4 + 'filename-test :', filename_test
            
        if opt == '-D':
            do_debug = True
            print ' '*4 + 'debug-mode : ON'

        if opt == '-m':
            do_multi_classify = True
            print ' '*4 + 'multi-classify : ON'

        if opt == '--no-sigmoid':
            do_apply_sigmoid = False
            print ' '*4 + 'no-sigmoid : ON'


# -----------------------------------------------------------------------------
# print usage of command
# -----------------------------------------------------------------------------
def printUsage():
    print 'usage: main.py [mode] [options]'
    
    print ' '*4 + 'mode (required) :'
    print ' '*8 + 'normal             train and classify (e.g. train development data and classify test data)'
    print ' '*8 + 'cross              cross-validation (e.g. development data)'

    print ' '*4 + 'option :'
    print ' '*8 + '-a [algorithm]     training algorithm, default:%s (optional)' % (ALGORITHM_LIST[0])
    print ' '*8 + '                     - without_classias: averaged perceptron implemented in Python. It can be used without installing Classias'
    print ' '*8 + '                     - lbfgs.logistic: L1/L2-regularized logistic regression using Classias'
    print ' '*8 + '                     - averaged_perceptron: averaged perceptron using Classias'
    print ' '*8 + '                     - pegasos.logistic: L2-regularized L1-loss SVM using Classias'
    print ' '*8 + '                     - pegasos.hinge: L2-regularized L1-loss SVM using Classias'
    print ' '*8 + '                     - truncated_gradient.logistic: L1-regularized logistic regression using Classias'
    print ' '*8 + '                     - truncated_gradient.hinge: L1-regularized L1-loss SVM using Classias'

    print ' '*8 + '-d [name]          development data (required)'
    print ' '*8 + '-g [int]           number of separation on cross-validation, default:10 (optional)'
    print ' '*8 + '-l [name]          output directory path, default:log (optional)'
    print ' '*8 + '-m                 multi-classification'
    print ' '*8 + '-p [name]=[value]  parameters for training (optional)'
    print ' '*8 + '-t [name]          test data (required for "normal mode")'
    print ' '*8 + '--no-sigmoid       do not apply sigmoid function to score'


# -----------------------------------------------------------------------------
# make directory for log-output
# -----------------------------------------------------------------------------
def makeLogDirectory():
    if not os.path.isdir(log_dir_name):
        os.makedirs(log_dir_name)


# -----------------------------------------------------------------------------
# get whether are filenames of data-sets inputted
# -----------------------------------------------------------------------------
def hasSetFilenameOfDataSet():
    global filename_dev, filename_test, mode
    
    if mode == 'normal':
        return (filename_dev != '') and (filename_test != '')
    else:
        return (filename_dev != '')


# ----------------------------------------------------------------------------
# get type of dataset.
# ----------------------------------------------------------------------------
def getDataType(filename):
    with open(filename) as fi:
        for line in fi:
            idx = line.find('label=')
            if idx > 0:
                label = line[idx+7:idx+8]
                if label == 'Y' or label == 'N':
                    return 'bc'
                else:
                    return 'mc'
    return False


def checkDataTypeNormal():
    type_dev  = getDataType(filename_dev)
    type_test = getDataType(filename_test)

    is_valid = (bool(type_dev) and bool(type_test) and type_dev==type_test)
    return (is_valid, type_dev)


def checkDataTypeCloss():
    type_dev  = getDataType(filename_dev)

    return (bool(type_dev), type_dev)


# -----------------------------------------------------------------------------
# get development-data.
#     OUTPUT : list of Pair
# -----------------------------------------------------------------------------
def getDevData():
    return read_xml.readXML(filename_dev)


# -----------------------------------------------------------------------------
# get test-data.
#     OUTPUT : list of Pair
# -----------------------------------------------------------------------------
def getTestData():
    return read_xml.readXML(filename_test)
